﻿
using System;
using System.Collections.Generic;
using System.Linq;
using Yes.Application.Article.Dto;
using Yes.Core.Extensions;
using Yes.Core.Helper;
using Yes.Core.Pager;
using Yes.Domain;
using Yes.Domain.Entity;
using Yes.Domain.Enum;


namespace Yes.Application.Article
{
    public class ArticleService : BaseService, IArticleService
    {
        private IRepository<ArticleEntity> _articleRepository;
        private IRepository<CategoryEntity> _categoryRepository;
        private IRepository<UserEntity> _userRepository;
        private IRepository<ArticleTagEntity> _articleTagRepository;
        private IRepository<TagEntity> _tagRepository;


        public ArticleService(IRepository<ArticleEntity> articleRepository, IRepository<CategoryEntity> categoryRepository,
            IRepository<UserEntity> userRepository,
            IRepository<ArticleTagEntity> articleTagRepository,
            IRepository<TagEntity> tagRepository)
        {
            _articleRepository = articleRepository;
            _categoryRepository = categoryRepository;
            _userRepository = userRepository;
            _articleTagRepository = articleTagRepository;
            _tagRepository = tagRepository;
        }

        public ArticleEntity GetArticle(int id)
        {
            return _articleRepository.Get(id);
        }

        public ResultDto Add(ArticleAddDto dto,int userId)
        {
            ArticleEntity article = null;
            if (dto.Id > 0)
            {
                article = _articleRepository.Get(dto.Id);
                if (article != null)
                {
                    article.CategoryId = dto.CategoryId;
                    article.Title = dto.Title;
                    article.Content = dto.Content;
                    article.Tag = dto.Tag;
                    article.Img = dto.Img;
                    article.ModifyDate = DateTime.Now;
                    article.UserId = userId;
                    article.Summary = dto.Summary;
                    if (string.IsNullOrEmpty(article.Summary))
                    {
                        article.Summary = StringHelper.ReplaceHtml(article.Content, 180).Trim();
                    }
                  
                    article.CanComment = dto.CanComment;
                    if (string.IsNullOrEmpty(article.Img))
                    {
                        var imgList = StringHelper.GetImgUrl(article.Content);
                        if (imgList.Count > 0)
                        {
                            article.Img = imgList.FirstOrDefault();
                        }
                    }
                    
                    if (!string.IsNullOrEmpty(article.Tag))
                    {
                        var tagList = _articleTagRepository.Query(p => p.ArticleId == article.Id).ToList();
                        foreach (var tagName in article.Tag.Replace(" ", ",").Replace("，", "").Replace("|", ",").Replace(";", ",").Replace("；", ",").Split(','))
                        {
                            if (string.IsNullOrEmpty(tagName))
                            {
                                continue;
                            }
                            var tag = _tagRepository.Query(p => p.Name == tagName).FirstOrDefault();
                            if (tag == null)
                            {
                                tag = new TagEntity { Name = tagName, CreateDate = DateTime.Now, PinYin = PinYinHelper.Get(tagName) };
                                _tagRepository.Insert(tag);
                            }
                            else
                            {
                                tagList = tagList.Where(p => p.TagId != tag.Id).ToList();
                            }
                            if (tag.Id > 0)
                            {
                                var articleTag = new ArticleTagEntity { ArticleId = article.Id, TagId = tag.Id };
                                _articleTagRepository.Insert(articleTag);
                            }
                        }
                        _articleTagRepository.Delete(p => p.ArticleId == article.Id && tagList.Select(x => x.TagId).Contains(p.TagId));
                    }
                    else
                    {
                        _articleTagRepository.Delete(p => p.ArticleId == article.Id);
                    }

                    _articleRepository.Update(article);
                }
            }

            if (article==null)
            {
                article = dto.MapTo<ArticleEntity>();
                article.PublishDate = DateTime.Now;
                article.ModifyDate = DateTime.Now;
                article.UserId = userId;
                article.Summary = StringHelper.ReplaceHtml(article.Content, 180);
                article.Status = dto.Status;
                if (string.IsNullOrEmpty(article.Img))
                {
                    var imgList = StringHelper.GetImgUrl(article.Content);
                    if (imgList.Count > 0)
                    {
                        article.Img = imgList.FirstOrDefault();
                    }
                }

                if (!string.IsNullOrEmpty(article.Tag))
                {
                    foreach (var tagName in article.Tag.Replace(" ", ",").Replace("，", "").Replace("|", ",").Replace(";", ",").Replace("；", ",").Split(','))
                    {
                        if (string.IsNullOrEmpty(tagName))
                        {
                            continue;
                        }
                        var tag = _tagRepository.Query(p => p.Name == tagName).FirstOrDefault();
                        if (tag == null)
                        {
                            tag = new TagEntity { Name = tagName, CreateDate = DateTime.Now, PinYin = PinYinHelper.Get(tagName) };
                            _tagRepository.Insert(tag);
                        }

                        if (tag.Id > 0)
                        {
                            var articleTag = new ArticleTagEntity { ArticleId = article.Id, TagId = tag.Id };
                            _articleTagRepository.Insert(articleTag);
                        }
                    }
                }
                _articleRepository.Insert(article);
            }
            var articleCount = _articleRepository.Count(x => x.CategoryId == article.CategoryId);

            var category = _categoryRepository.Query(x => x.Id == article.CategoryId).FirstOrDefault();
            if (category != null)
            {
                category.ArticleCount = articleCount;
                _categoryRepository.Update(category);
            }




            return new ResultDto
            {
                Status = true
            };
        }


        public PageInfo<ArticleDto> GetPageInfo(ArticlePagerDto dto)
        {
            var articleQuery = _articleRepository.TableNoTracking;
            if (!string.IsNullOrEmpty(dto.Keyword))
            {
                articleQuery = articleQuery.Where(p => p.Title.Contains(dto.Keyword));
            }
            if (dto.IsRecycle)
            {
                articleQuery = articleQuery.Where(p => p.Status == ArticleStatusEnum.Deleted);
            }
            else if (dto.IsDraft)
            {
                articleQuery = articleQuery.Where(p => p.Status == ArticleStatusEnum.Draft);
            }
            else
            {
                articleQuery = articleQuery.Where(p => p.Status == ArticleStatusEnum.Normal);
            }

            if (dto.Year > 0)
            {
                articleQuery = articleQuery.Where(p => p.PublishDate.Year== dto.Year);
            }

            if (dto.Month > 0)
            {
                articleQuery = articleQuery.Where(p => p.PublishDate.Month == dto.Month);
            }

            if (dto.UserId > 0)
            {
                articleQuery = articleQuery.Where(p => p.UserId == dto.UserId);
            }

            if (dto.TagId > 0)
            {
                var articleIds = _articleTagRepository.Query(p => p.TagId == dto.TagId).Select(x => x.ArticleId).ToList();
                articleQuery = articleQuery.Where(p => articleIds.Contains(p.Id));
            }

            var categoryQuery = _categoryRepository.TableNoTracking;
            if (dto.CategoryId > 0)
            {
                articleQuery = articleQuery.Where(p => p.CategoryId == dto.CategoryId);
            }

            var query = from article in articleQuery
                        join category in categoryQuery.DefaultIfEmpty()
                    on article.CategoryId equals category.Id into categoryTemp
                from cate in categoryTemp.DefaultIfEmpty()
                join user in _userRepository.TableNoTracking.DefaultIfEmpty()
                    on article.UserId equals user.Id into userTemp
                from u in userTemp.DefaultIfEmpty()
                select new ArticleDto()
                {
                    CategoryName = cate.Name,
                    SortId = article.SortId,
                    CategoryId = article.CategoryId,
                    ModifyDate = article.ModifyDate,
                    PublishDate = article.PublishDate,
                    Title = article.Title,
                    Content = article.Content,
                    Id = article.Id,
                    ReadCount = article.ReadCount,
                    Summary = article.Summary,
                    CommentCount = article.CommentCount,
                    CanComment = article.CanComment,
                    UserId = article.UserId,
                    UserName = u==null?"":u.NickName,
                    Img = article.Img
                };

            return query.OrderByDescending(p => p.Id).Paged(dto.PageIndex, dto.PageSize, query.Count());


        }

        
        public ResultDto Remove(List<int> ids)
        {
            if (ids.Count > 0)
            {
                _articleRepository.Update(x => ids.Contains(x.Id), p => new ArticleEntity { Status = ArticleStatusEnum.Deleted });


                var article = _articleRepository.Get(ids.First());
                if (article != null)
                {
                    var articleCount = _articleRepository.Count(x => x.CategoryId == article.CategoryId && x.Status == ArticleStatusEnum.Normal);
                    _categoryRepository.Update(x => x.Id == article.CategoryId, p => new CategoryEntity { ArticleCount = articleCount });
                }
            }


            return new ResultDto
            {
                Status = true
            };
        }

        public ResultDto Delete(List<int> ids)
        {
            _articleRepository.Delete(x => ids.Contains(x.Id) && x.Status== ArticleStatusEnum.Deleted);
            return new ResultDto
            {
                Status = true
            };
        }

        public ResultDto Recovery(List<int> ids)
        {
            if (ids.Count > 0)
            {
                _articleRepository.Update(x => ids.Contains(x.Id), p => new ArticleEntity { Status = ArticleStatusEnum.Normal });

                var article = _articleRepository.Get(ids.First());
                if (article != null)
                {
                    var articleCount = _articleRepository.Count(x => x.CategoryId == article.CategoryId && x.Status == ArticleStatusEnum.Normal);
                    _categoryRepository.Update(x => x.Id == article.CategoryId, p => new CategoryEntity { ArticleCount = articleCount });
                }
            }


            return new ResultDto
            {
                Status = true
            };
        }

        public List<ArchiveDto> GetArchiveList()
        {
            var archives = new List<ArchiveDto>();
            var dates = _articleRepository.Query(x=>x.Status== ArticleStatusEnum.Normal).OrderByDescending(x => x.PublishDate).Select(x => x.PublishDate).ToList();
            foreach (var date in dates)
            {
                var archive = new ArchiveDto
                {
                    ArticleCount = 1,
                    Month = date.Month,
                    Year = date.Year
                };
                if (archives.Count(p => p.Year == archive.Year && p.Month == archive.Month) == 0)
                {
                    archives.Add(archive);
                }
                else
                {
                    archives.First(p => p.Year == archive.Year && p.Month == archive.Month).ArticleCount++;
                }
            }
            return archives;
        }


        public List<TagDto> GetTagList()
        {
            return _tagRepository.TableNoTracking.Select(x => new TagDto { Id = x.Id, Name = x.Name }).ToList();
        }

        public void UpdateReadCount(ArticleEntity article, bool useCache = true)
        {
            string key = "UpdateReadCount_" + article.Id;
            string value = "1";
            if (useCache)
            {
                var hasUpdate = CookiesHelper.GetCookieValue(key);
                if (hasUpdate == value)
                {
                    return;
                }
            }
            article.ReadCount++;
            _articleRepository.Update(article);

            CookiesHelper.SetCookie(key, value, DateTime.Now.AddHours(24));
        }
    }
}
